package com.see.client;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.net.Socket;
import java.util.HashMap;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;

import org.slf4j.LoggerFactory;
import org.slf4j.Logger;

import com.see.domain.MessegeParser;
import com.see.domain.Order;
import com.see.domain.Protocol;
import com.see.exception.MessegeFeedException;
import com.see.exception.UserExistException;
import com.see.servise.SEEServise;



public class ClientSocketConnection {
	
	private TradingClientImpl tradingClient;
	private Set<Listener> listnersarray =  new CopyOnWriteArraySet<>();
    private Socket socket;
    public BufferedReader bufferedReader;
	public PrintWriter printWriter;
	private volatile boolean connectionClose = false;
	private Thread intputThread;
	private static Logger logger = LoggerFactory.getLogger(ClientSocketConnection.class);
	
	public ClientSocketConnection(Socket socket, Listener listner,
			TradingClientImpl tradingClient) throws IOException {
		
		this.tradingClient = tradingClient;
		this.listnersarray.add(listner);
		this.socket = socket;
		this.bufferedReader = new BufferedReader(new InputStreamReader(
				socket.getInputStream()));
		this.printWriter = new PrintWriter(socket.getOutputStream(), true);
	}
    

	public void run() {
		
    	intputThread = new Thread(new Runnable() {
            @Override
            public void run() {
                    while(!Thread.interrupted()) {
                    	receiveMessage();
                    }
            }
		 });
    	intputThread.start();
    	
    	
    }
	
	public void close(){
		if (!connectionClose) {
			try {
				intputThread.interrupt();
				connectionClose = true;
				logger.info("client msg: disconected");
				socket.shutdownInput();
				socket.shutdownOutput();
				socket.close();
				bufferedReader.close();
				printWriter.close();
				socket = null;
				Thread.currentThread().interrupt();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}
	
    
	public synchronized void receiveMessage() {
		String msg;
		try {
			msg = bufferedReader.readLine();
			if(msg == null || msg.equals(""))
				throw new IOException("Null or Empty msg from server");
			logger.info("Client input: " + msg);
			try {
				
				HashMap<String, String> paramMap = new MessegeParser(msg).parseMsg();
				String cmd = paramMap.get(MessegeParser.MsgFields.TYPEMSG.name());
				if (cmd == null)
					throw new MessegeFeedException("command_type_miss");
			
				if (listnersarray != null) {
					for (Listener listern : listnersarray) {
						listern.notificate(paramMap);
					}
				}
				

			} catch (MessegeFeedException e) {
				logger.error(e.getMessage());
				
			}
			
		} catch (IOException e) {
			logger.error(e.getMessage());
			close();
		}
	}

	public void sendMessage(String msg) {
		logger.info("client output: " + msg);
		printWriter.println(msg);
	}
	
	
	public void login() throws UserExistException, MessegeFeedException {
		
		LoginListner loginListener = new LoginListner(tradingClient);
		addLisner(loginListener);
		
		String msg = Protocol.client_loginmsg(tradingClient.getUserName());
				
		sendMessage(msg);
		
		loginListener.waitForComplete();
		
		if(!loginListener.isLoginSuccsess()){
			String result = loginListener.getListnerResult();
			if(result.equals(Protocol.ERROR_USEREXIST))
				throw new UserExistException(Protocol.ERROR_USEREXIST);
			throw new MessegeFeedException(loginListener.getListnerResult());
		}
		
		
		removeLisner(loginListener);
		
	}

	public int sendOrder(Order order) throws MessegeFeedException {
		int orderid = 0;
		
		SendOrderListener sendOrderListener = new SendOrderListener(tradingClient);
		addLisner(sendOrderListener);
		
		String msg = Protocol.client_sendorder(order);
		
		sendMessage(msg);
		
		sendOrderListener.waitForComplete();
		
		if(!sendOrderListener.isSendOrderSuccsess()){
			throw new MessegeFeedException(sendOrderListener.getListnerResult());
		}
		
		orderid = sendOrderListener.getIdorder();
		
		removeLisner(sendOrderListener);
		
		return orderid;
	}
	
	public void addLisner(Listener listener) {
		listnersarray.add(listener);
	}

	public void removeLisner(Listener listener) {
		listnersarray.remove(listener);
	}
	
	

}
